Scaffolding code

EF Core allows us to scaffold a model in code, based on an existing database.

Because F# allows multiple ways of representing an object, we are able to provide configuration options for how that generated code is formed.

Record vs Class type

If we wanted to model a blog post with an Id, Title and Content we could do it as a record type

1: 
2: 
3: 
4: 
5: 
type BlogPostRecord = {
    Id : int
    Title: string
    Content: string
}

Or we could do it as a class type, that would behave more like how a C# class would

 1: 
 2: 
 3: 
 4: 
 5: 
 6: 
 7: 
 8: 
 9: 
10: 
type BlogPostClass() =

    [<DefaultValue>] val mutable private _Id : int
    member this.Id with get() = this._Id and set v = this._Id <- v

    [<DefaultValue>] val mutable private _Title : string
    member this.Title with get() = this._Title and set v = this._Title <- v

    [<DefaultValue>] val mutable private _Content : string
    member this.Content with get() = this._Content and set v = this._Content <- v

Similarly, if we had a nullable column, for instance of type Guid, it might be specified as either Nullable<Guid> or in more idiomatic F#, as guid option

Again, we provide options for how these should be scaffolded.

Scaffolding Options

We provide EntityFramework.FSharp.ScaffoldOptions to specify how we want to create our scaffolded code.

By default we scaffold record types with nullable columns represented as option types, but this can be overridden.

To do this, you'll need your own implementation of IDesignTimeServices, where we can declare a ScaffoldOptions object.

The ScaffoldOptions.Default object is equivalent to ScaffoldOptions (ScaffoldTypesAs = RecordType, ScaffoldNullableColumnsAs = OptionTypes)

If you are happy with the default of record-type objects with option properties then you will not need to implement this at all, it is already handled automatically for you.

 1: 
 2: 
 3: 
 4: 
 5: 
 6: 
 7: 
 8: 
 9: 
10: 
11: 
12: 
13: 
14: 
15: 
16: 
17: 
18: 
19: 
20: 
21: 
22: 
23: 
module DesignTimeServices =

    open Microsoft.Extensions.DependencyInjection
    open Microsoft.EntityFrameworkCore.Design
    open EntityFrameworkCore.FSharp

    type DesignTimeServices() =
        interface IDesignTimeServices with
            member __.ConfigureDesignTimeServices(serviceCollection: IServiceCollection) =
                
                // The default behaviour can be specified by calling
                let fSharpServices = EFCoreFSharpServices.Default

                // Or we can define a ScaffoldOptions use that instead
                let scaffoldOptions =
                    ScaffoldOptions (
                        ScaffoldTypesAs = ScaffoldTypesAs.ClassType,
                        ScaffoldNullableColumnsAs = ScaffoldNullableColumnsAs.NullableTypes)

                let fSharpServices = EFCoreFSharpServices.WithScaffoldOptions scaffoldOptions

                fSharpServices.ConfigureDesignTimeServices serviceCollection
                ()
type BlogPostRecord =
  { Id: int
    Title: string
    Content: string }
BlogPostRecord.Id: int
Multiple items
val int : value:'T -> int (requires member op_Explicit)

--------------------
type int = int32

--------------------
type int<'Measure> = int
BlogPostRecord.Title: string
Multiple items
val string : value:'T -> string

--------------------
type string = System.String
BlogPostRecord.Content: string
Multiple items
type BlogPostClass =
  new : unit -> BlogPostClass
  val mutable private _Id: int
  val mutable private _Title: string
  val mutable private _Content: string
  member Content : string
  member Id : int
  member Title : string
  member Content : string with set
  member Id : int with set
  member Title : string with set

--------------------
new : unit -> BlogPostClass
Multiple items
type DefaultValueAttribute =
  inherit Attribute
  new : unit -> DefaultValueAttribute
  new : check:bool -> DefaultValueAttribute
  member Check : bool

--------------------
new : unit -> DefaultValueAttribute
new : check:bool -> DefaultValueAttribute
BlogPostClass._Id: int
val this : BlogPostClass
val set : elements:seq<'T> -> Set<'T> (requires comparison)
val v : int
BlogPostClass._Title: string
val v : string
BlogPostClass._Content: string
module DesignTimeServices

from ScaffoldAsTypes
namespace Microsoft
namespace Microsoft.Extensions
namespace Microsoft.Extensions.DependencyInjection
namespace Microsoft.EntityFrameworkCore
namespace Microsoft.EntityFrameworkCore.Design
namespace EntityFrameworkCore
namespace EntityFrameworkCore.FSharp
Multiple items
type DesignTimeServices =
  interface IDesignTimeServices
  new : unit -> DesignTimeServices

--------------------
new : unit -> DesignTimeServices
type IDesignTimeServices =
  member ConfigureDesignTimeServices : serviceCollection:IServiceCollection -> unit
val serviceCollection : IServiceCollection
type IServiceCollection =
  inherit IList<ServiceDescriptor>
  inherit ICollection<ServiceDescriptor>
  inherit IEnumerable<ServiceDescriptor>
  inherit IEnumerable
val fSharpServices : IDesignTimeServices
Multiple items
type EFCoreFSharpServices =
  interface IDesignTimeServices
  new : unit -> EFCoreFSharpServices
  new : scaffoldOptions:ScaffoldOptions -> EFCoreFSharpServices
  static member WithScaffoldOptions : scaffoldOptions:ScaffoldOptions -> IDesignTimeServices
  static member Default : IDesignTimeServices

--------------------
new : unit -> EFCoreFSharpServices
new : scaffoldOptions:ScaffoldOptions -> EFCoreFSharpServices
property EFCoreFSharpServices.Default: IDesignTimeServices with get
val scaffoldOptions : ScaffoldOptions
Multiple items
type ScaffoldOptions =
  new : unit -> ScaffoldOptions
  member ScaffoldNullableColumnsAs : ScaffoldNullableColumnsAs
  member ScaffoldTypesAs : ScaffoldTypesAs
  member ScaffoldNullableColumnsAs : ScaffoldNullableColumnsAs with set
  member ScaffoldTypesAs : ScaffoldTypesAs with set
  static member Default : ScaffoldOptions

--------------------
new : unit -> ScaffoldOptions
type ScaffoldTypesAs =
  | RecordType
  | ClassType
union case ScaffoldTypesAs.ClassType: ScaffoldTypesAs
type ScaffoldNullableColumnsAs =
  | OptionTypes
  | NullableTypes
union case ScaffoldNullableColumnsAs.NullableTypes: ScaffoldNullableColumnsAs
static member EFCoreFSharpServices.WithScaffoldOptions : scaffoldOptions:ScaffoldOptions -> IDesignTimeServices
IDesignTimeServices.ConfigureDesignTimeServices(serviceCollection: IServiceCollection) : unit